﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;

namespace LowLevelGraphics.Filter
{
    //TODO: windowed sinc filter, test
    /// <summary>
    /// 
    /// </summary>
    public class WindowedSinc : BaseImageFilter
    {
        protected int m_nWinSize = 24; //window size
        protected double m_CutoffFrequency = 0.5; //cutoff frequency
        protected bool m_bShowFilter = false;

        /// <summary>
        /// default constructor
        /// </summary>
        public WindowedSinc()
        {
        }

        /// <summary>
        /// used by clone to create a deep copy
        /// </summary>
        /// <param name="_windowedSinc"></param>
        internal WindowedSinc(WindowedSinc _windowedSinc)
        {
            this.m_nWinSize = _windowedSinc.m_nWinSize;
            this.m_CutoffFrequency = _windowedSinc.m_CutoffFrequency;
            this.m_bShowFilter = _windowedSinc.m_bShowFilter;
        }

        /// <summary>
        /// the size of the win.
        /// </summary>
        /// <value>The size of the win.</value>
        public int WinSize
        {
            get { return m_nWinSize; }
            set { m_nWinSize = value; }
        }

        /// <summary>
        /// Gets or sets the cutoff frequency.
        /// </summary>
        /// <value>The cutoff frequency.</value>
        public double CutoffFrequency
        {
            get { return m_CutoffFrequency; }
            set { m_CutoffFrequency = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            ConvolveFrames(_bitmap, m_nWinSize, 0.5 * m_CutoffFrequency);
            return _bitmap;
        }

        /// <summary>
        /// Convolves the frames.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="winSize">Size of the win.</param>
        /// <param name="fc">The fc.</param>
        protected void ConvolveFrames(UnsafeBitmap _bitmap, int winSize, double fc)
        {
            UnsafeBitmap bitmapCloned = (UnsafeBitmap)_bitmap.Clone();
            int nHeight = _bitmap.Height;
            int nWidth = _bitmap.Width;

            double PI = Math.PI;
            double[] h = new double[(winSize + 1)];
            double sumh = 0;
            int i;
            for (i = 0; i <= winSize; i++)
            {
                if (i == winSize / 2)
                {
                    h[i] = 2 * PI * fc;
                }
                else
                {
                    h[i] = Math.Sin(2 * PI * fc * (i - winSize / 2)) / (i - winSize / 2);
                }
                h[i] = h[i] * (0.54 - 0.46 * Math.Cos(2 * PI * i / winSize));
                //IJ.log(i+"\t"+h[(int)i]);
                sumh += h[i];
            }

            Color color = Color.Transparent;
            int x = 0;
            int y = 0;
            int z = 0;
            for (i = 0; i < winSize; i++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    for (y = 0; y < nHeight; y++)
                    {
                        color = bitmapCloned.GetPixel(x, y);
                        for (z = 0; z < 3; z++)
                        {
                            if (i == 0)
                            {
                                _bitmap[x, y, z] = 0;
                            }
                            double dTest = (bitmapCloned[x, y, z] & 0xff) * h[i] / sumh;
                            byte floatToBinaryInt = (byte)FloatToBinaryInt((float)dTest);
                            _bitmap[x, y, z] += floatToBinaryInt;
                            //Debug.WriteLine(_bitmap[x, y, z]);
                        }
                        //Debug.WriteLine("");
                    }
                }
            }
        }

        /// <summary>
        /// used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new WindowedSinc(this);
        }

        /// <summary>
        /// Floats to binary int.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public unsafe uint FloatToBinaryInt(float value)
        {
            uint uiNum = *((uint*)&value);
            return uiNum;
        }

        /// <summary>
        /// Binaries the int to float.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public unsafe float BinaryIntToFloat(uint value)
        {
            float fNum = *((float*)&value);
            return fNum;
        }
    }
}
